/*
 * Copyright (C) 2009 Kristopher T Babic
 *
 * This program is free software; you can redistribute it and/or modify it under the terms of
 * the GNU General Public License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with this program;
 * if not, see <http://www.gnu.org/licenses>.
 */

package edu.idp.client.model;

/**
 *
 * @author Kristopher T Babic
 */
public class Matrix4D {

    private float[][] matrix;

    static final double pi = 3.14159265;

    public Matrix4D() {
        matrix = new float[4][4];
        setIdentity();
    }

    public void setIdentity() {
        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 4; j++) {
                if (i == j)
                    setIndex(i, j, 1);
                else
                    setIndex(i, j, 0);
            }
        }
    }

    public boolean isIdentity() {
        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 4; j++) {
                if (i == j && getIndex(i, j) != 1)
                    return false;
                else if (getIndex(i, j) != 0)
                    return false;
            }
        }
        return true;
    }

    public float getIndex(int i, int j) {
        return matrix[i][j];
    }

    public void setIndex(int i, int j, float val) {
        matrix[i][j] = val;
    }

    public void setScale(float x, float y, float z) {
        Matrix4D temp = new Matrix4D();

        temp.setIndex(0, 0, x);
        temp.setIndex(1, 1, y);
        temp.setIndex(2, 2, z);
        mult(temp);
    }

    public void setScale(float scale) {
        Matrix4D temp = new Matrix4D();

        for (int i = 0; i < 3; i++)
            temp.setIndex(i, i, scale);
        mult(temp);
    }

    public void setTranslate(float x, float y, float z) {
        Matrix4D temp = new Matrix4D();

        temp.setIndex(3, 0, x);
        temp.setIndex(3, 1, y);
        temp.setIndex(3, 2, z);
        mult(temp);
    }

    public void setTranslate(float t) {
        Matrix4D temp = new Matrix4D();

        for (int i = 0; i < 3; i++)
            temp.setIndex(3, i, t);
        mult(temp);
    }

    public void setZRot(float theta) {
        float angle = (float) ((theta * pi) / 180.0f);
        Matrix4D temp = new Matrix4D();

        temp.setIndex(0, 0, (float) Math.cos(angle));
        temp.setIndex(0, 1, (float) -Math.sin(angle));
        temp.setIndex(1, 0, (float) Math.sin(angle));
        temp.setIndex(1, 1, (float) Math.cos(angle));

        mult(temp);
    }

    public void setYRot(float theta) {
        float angle = (float) ((theta * pi) / 180.0f);
        Matrix4D temp = new Matrix4D();

        temp.setIndex(0, 0, (float) Math.cos(angle));
        temp.setIndex(0, 2, -(float) Math.sin(angle));
        temp.setIndex(2, 0, (float) Math.sin(angle));
        temp.setIndex(2, 2, (float) Math.cos(angle));
        mult(temp);
    }

    public void setXRot(float theta) {
        float angle = (float) ((theta * pi) / 180.0f);
        Matrix4D temp = new Matrix4D();

        temp.setIndex(1, 1, (float) Math.cos(angle));
        temp.setIndex(1, 2, -(float) Math.sin(angle));
        temp.setIndex(2, 1, (float) Math.sin(angle));
        temp.setIndex(2, 2, (float) Math.cos(angle));
        mult(temp);
    }

    public void mult(Matrix4D m2) {

        Matrix4D retMatrix = new Matrix4D();

        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 4; j++) {
                float temp = 0;

                for (int k = 0; k < 4; k++)
                    temp += getIndex(i, k) * m2.getIndex(k, j);

                retMatrix.setIndex(i, j, temp);
            }
        }

        copyMatrix(retMatrix);
    }

    public float[] mult(float[] vect) {

        float tmp;
        float vr[] = new float[4];

        for (int i = 0; i < 4; i++) {
            tmp = 0.0f;
            for (int j = 0; j < 4; j++)
                tmp += getIndex(j, i) * vect[j];
            vr[i] = tmp;
        }

        return vr;
    }

    public void copyMatrix(Matrix4D m2) {
        for (int i = 0; i < 4; i++)
            for (int j = 0; j < 4; j++)
                setIndex(i, j, m2.getIndex(i, j));
    }

    public String toString() {
        String retString = "[";

        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 4; j++) {
                retString += getIndex(i, j);
                if (j < 3)
                    retString += ",";
            }
            if (i < 3)
                retString += ";\n ";
        }
        retString += "]";

        return retString;

    }
}
			